/*
 * The MIT License (MIT)
 * Copyright © 2022 Walkline Wang (https://walkline.wang)
 * Gitee: https://gitee.com/walkline/ramcu-mechanical-keypad
 */
#include "app_common.h"
#include "ch9329/ch9329.h"
#include "key_matrix/key_matrix.h"
#include "uart_common/uart_common.h"

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

/**
 * 私有函数
 */
void timer_matrix_init(void);
void blink_led(void);

/**
 *
 * GPT 间隔时间计算方法
 *
 * 如设置 10ms 间隔触发一次回调函数，period=10
 * 则公式为：1秒 / (period / 1000毫秒)
 * 		1 / (period / 1000) = 100，这是以 hz 为单位需要填写的数字
 *
 * 如需要 raw_counts 作为单位，则用 GPT 时钟源除以上边的结果
 * 		48000000 / 100 = 480000，这是以 raw_counts 为单位需要填写的数字
 *
 * */

/**
 * 私有变量
 */
/* 计数器 */
static volatile uint8_t timer_count			= 0;
static volatile uint8_t scan_count			= 0;
static volatile uint8_t chip_status_count	= 0;
static volatile uint16_t blink_count		= 0;

static fsp_err_t err;

void timer_matrix_init(void)
{
	err = R_GPT_Open(&g_timer_periodic_ctrl, &g_timer_periodic_cfg);

	if(FSP_SUCCESS != err) printf("gpt_open failed\r\n");
	assert(FSP_SUCCESS == err);

	sleep_ms(5);
	(void) R_GPT_Start(&g_timer_periodic_ctrl);
	sleep_ms(5);

	printf("timer_matrix started\r\n");
}

void timer_periodic_callback(timer_callback_args_t *p_args)
{
	if (TIMER_EVENT_CYCLE_END == p_args->event) {timer_count = 1;}
}

void blink_led() {
	static bool led_status = true;

	led_status ? set_io_low(io_num_lock) : set_io_high(io_num_lock);
	led_status = !led_status;
}

void hal_entry(void)
{
	uart_console_init();
	uart_usb_hid_init();
	timer_matrix_init();
	ch9329_reset();
	sleep_ms(10);

	g_uart_usb_hid_recv_flag = true;
	ch9329_check_status();

#if DEBUG
	printf("\r\nCH9329 INFO:\r\n"\
		   "      version: %s\r\n"\
		   "       usb on: %d\r\n"\
		   "     num_lock: %d\r\n"\
		   "    caps_lock: %d\r\n"\
		   "  scroll_lock: %d\r\n\r\n",
		   g_chip_info.version, g_chip_info.usb_status, g_chip_info.num_lock_status, g_chip_info.caps_lock_status, g_chip_info.scroll_lock_status);
#endif

	while (true) {
		if (timer_count == 1) {
			timer_count = 0;
			scan_count++;
			blink_count++;
			chip_status_count++;
		}

		if (chip_status_count >= 10) {
			chip_status_count = 0;
			ch9329_check_status();
		}

		if (scan_count >= SCAN_PERIOD) {
			scan_count = 0;
			matrix_scan();

			if (g_keycode_changed) {
				g_keycode_changed = false;
				ch9329_send_kb_data();
			}
		}

		if (blink_count >= 500) {
			blink_count = 0;
//			blink_led();
		}
	}

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP->DFLCTL = 1U;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
    }
}

#if BSP_TZ_SECURE_BUILD

BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{

}
#endif
